package com.stars.easyms.base.util;

import com.stars.easyms.base.exception.IllegalPropertiesException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;

/**
 * 在代码中根据application.yaml属性动态加载占位符
 *
 * @author guoguifang
 * @date 2018-10-19 10:07
 * @since 1.0.0
 */
public final class PropertyPlaceholderUtil {

    private static final Logger logger = LoggerFactory.getLogger(PropertyPlaceholderUtil.class);

    private static Environment environment;

    /**
     * 在代码中根据application.yaml属性动态加载占位符
     *
     * @param placeholderStr 包含占位符的字符串
     * @return 解析后的字符串
     */
    public static String replace(String placeholderStr) {
        return replace(placeholderStr, true);
    }

    /**
     * 在代码中根据application.yaml属性动态加载占位符
     *
     * @param placeholderStr 包含占位符的字符串
     * @param defaultStr     如果不存在默认的返回值
     * @return 解析后的字符串
     */
    public static String replace(String placeholderStr, String defaultStr) {
        try {
            String replaceValue = replace(placeholderStr, false);
            if (StringUtils.isBlank(replaceValue)) {
                return defaultStr;
            }
            return replaceValue;
        } catch (Exception e) {
            logger.error("Get placeholder [{}] failure!", placeholderStr, e);
            return defaultStr;
        }
    }

    /**
     * 在代码中根据application.yaml属性动态加载占位符
     *
     * @param placeholderStr 包含占位符的字符串
     * @param isRequired     是否是必须的，如果是必须的若没有配置则返回异常，如果不是必须的则不返回异常
     * @return 解析后的字符串
     */
    private static String replace(String placeholderStr, boolean isRequired) {
        if (StringUtils.isBlank(placeholderStr)) {
            if (isRequired) {
                throw new IllegalStateException("Required key cannot be blank!");
            }
            return placeholderStr;
        }
        if (!placeholderStr.contains("${") || !placeholderStr.contains("}")) {
            if (placeholderStr.contains(".")) {
                if (isRequired) {
                    return getRequiredProperty(placeholderStr);
                }
                return getProperty(placeholderStr);
            }
            return placeholderStr;
        } else {
            char[] src = placeholderStr.toCharArray();
            int offset = 0;
            int start = placeholderStr.indexOf("${", offset);
            final StringBuilder builder = new StringBuilder();
            StringBuilder expression = null;
            while (start > -1) {
                if (expression == null) {
                    expression = new StringBuilder();
                } else {
                    expression.setLength(0);
                }
                builder.append(src, offset, start - offset);
                offset = start + 2;
                int end = placeholderStr.indexOf('}', offset);
                if (end > -1 && end > offset) {
                    expression.append(src, offset, end - offset);
                }
                if (end == -1) {
                    builder.append(src, start, src.length - start);
                    offset = src.length;
                } else {
                    if (isRequired) {
                        builder.append(getRequiredProperty(expression.toString()));
                    } else {
                        builder.append(getProperty(expression.toString()));
                    }
                    offset = end + 1;
                }
                start = placeholderStr.indexOf("${", offset);
            }
            if (offset < src.length) {
                builder.append(src, offset, src.length - offset);
            }
            return builder.toString();
        }
    }

    private static String getProperty(String key) {
        String value = getEnvironment().getProperty(key);
        if (StringUtils.isBlank(value)) {
            return "";
        }
        return value;
    }

    private static String getRequiredProperty(String requiredKey) {
        String value = getEnvironment().getProperty(requiredKey);
        if (StringUtils.isBlank(value)) {
            throw new IllegalPropertiesException("Please configure [{}] in the properties or yaml file!", requiredKey);
        }
        return value;
    }

    private static Environment getEnvironment() {
        if (environment == null) {
            try {
                environment = ApplicationContextHolder.getApplicationContext().getBean(Environment.class);
            } catch (Exception e) {
                logger.error("Get Environment instance failure!", e);
                System.exit(1);
            }
        }
        return environment;
    }

    public static void setEnvironment(Environment environment) {
        PropertyPlaceholderUtil.environment = environment;
    }

}
